/*
 * Copyright 2010 Aekold Helbrass
 * 
 * This file is part of RosterComposer.
 * 
 * RosterComposer is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * RosterComposer is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with RosterComposer.  If not, see <http://www.gnu.org/licenses/>.
 */
package org.heresylabs.rostercomposer;

import java.awt.BorderLayout;
import java.awt.Component;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JToolBar;
import javax.swing.table.AbstractTableModel;
import org.heresylabs.rostercomposer.actions.ActionFactory;
import org.heresylabs.rostercomposer.roster.EntryNumberListener;
import org.heresylabs.rostercomposer.roster.EntryOptionsListener;
import org.heresylabs.rostercomposer.roster.RosterEntry;
import org.heresylabs.rostercomposer.units.Army;
import org.heresylabs.rostercomposer.units.Category;
import org.heresylabs.rostercomposer.units.Option;
import org.heresylabs.rostercomposer.units.Unit;

/**
 *
 * @author Aekold Helbrass <Helbrass@gmail.com>
 */
public class Composer extends JPanel implements EntryNumberListener, EntryOptionsListener {

    private final Army army;
    private final List<RosterEntry> roster = new ArrayList<RosterEntry>(20);
    private final RosterTableModel rosterTableModel = new RosterTableModel();
    private final TotalPointsComponent totalPointsLabel = new TotalPointsComponent();
    private final UnitPanel unitPanel;
    private int currentSelectedRow = -1;
    private RosterEntry currentSelectedEntry;

    public Composer(Army army, List<RosterEntry> roster) {
        this(army);
        if (roster != null) {
            this.roster.addAll(roster);
            rosterTableModel.fireTableDataChanged();
            fireCostChanged();
        }
    }

    public Composer(Army army) {
        super(new BorderLayout());
        setBorder(BorderFactory.createEmptyBorder(6, 6, 6, 6));
        this.army = army;

        unitPanel = new UnitPanel(this);

        UnitsListPanel unitsListPanel = new UnitsListPanel(this);

        JScrollPane bottomScroll = new JScrollPane(unitPanel);
        bottomScroll.getVerticalScrollBar().setUnitIncrement(13);

        JSplitPane split = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, new RosterPanel(this, rosterTableModel), bottomScroll);
        split.setResizeWeight(0.5);
        split.setDividerLocation(200);

        JSplitPane mainSplit = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, unitsListPanel, split);
        mainSplit.setResizeWeight(0.3);
        mainSplit.setDividerLocation(200);
        mainSplit.setOneTouchExpandable(true);

        super.add(mainSplit, BorderLayout.CENTER);

        super.add(createToolBar(), BorderLayout.NORTH);
    }

    void fireCostChanged() {
        int cost = 0;

        if (currentSelectedEntry != null) {
            // recalculating cost of current unit:
            currentSelectedEntry.calculateCost();
            // updating table row:
            rosterTableModel.fireTableRowsUpdated(currentSelectedRow, currentSelectedRow);
        }

        for (int i = 0; i < roster.size(); i++) {
            RosterEntry rosterEntry = roster.get(i);
            // unit cost is calculated on unit change, we're just getting already calculated cost:
            cost += rosterEntry.getCost();
        }

        totalPointsLabel.setCost(cost);
    }

    void select(int row) {
        // clearing entry listeners:
        if (currentSelectedEntry != null) {
            currentSelectedEntry.clearListeners();
        }
        // minor optimization, maybe will delete it in future:
        currentSelectedRow = row;
        RosterEntry entry = roster.get(currentSelectedRow);
        currentSelectedEntry = entry;
        entry.addOptionsListener(this);
        entry.addNumberListener(this);
        unitPanel.setRosterEntry(entry);
    }

    void addUnit(Unit unit, Category category) {
        RosterEntry entry = new RosterEntry(unit, category);
        int index = roster.size();
        roster.add(entry);
        rosterTableModel.fireTableRowsInserted(index, index);
        fireCostChanged();
    }

    void moveUp(int row) {
        Collections.swap(roster, row, row - 1);
        rosterTableModel.fireTableRowsUpdated(row, row - 1);
    }

    void moveDown(int row) {
        Collections.swap(roster, row, row + 1);
        rosterTableModel.fireTableRowsUpdated(row, row + 1);
    }

    RosterEntry getRosterEntry(int index) {
        return roster.get(index);
    }

    void deleteRosterEntry(int index) {
        if (currentSelectedEntry != null) {
            currentSelectedEntry.clearListeners();
            currentSelectedEntry = null;
        }
        roster.remove(index);
        rosterTableModel.fireTableRowsDeleted(index, index);
        unitPanel.setRosterEntry(null);
        fireCostChanged();
    }

    public JComponent getTotalPointsLabel() {
        return totalPointsLabel;
    }

    private Component createToolBar() {

        JToolBar mainToolBar = new JToolBar();
        mainToolBar.setFloatable(false);
        mainToolBar.setRollover(true);
        mainToolBar.add(ActionFactory.getNewAction());
        mainToolBar.add(ActionFactory.getOpenAction());
        mainToolBar.add(ActionFactory.getSaveAction());
        mainToolBar.add(ActionFactory.getPreviewCompactAction());
        mainToolBar.add(ActionFactory.getPreviewSimpleAction());

        Box box = Box.createHorizontalBox();
        box.add(mainToolBar);
        box.add(Box.createHorizontalGlue());
        return box;
    }

    @Override
    public void fireNumberChanged(int number) {
        fireCostChanged();
    }

    @Override
    public void fireOptionChanged(Option option, boolean added) {
        fireCostChanged();
    }

    private class RosterTableModel extends AbstractTableModel {

        private final String[] COLUMNS = {"Cost", "Category", "Name", "Number", "Options"};

        @Override
        public int getRowCount() {
            return roster.size();
        }

        @Override
        public int getColumnCount() {
            return COLUMNS.length;
        }

        @Override
        public String getColumnName(int column) {
            return COLUMNS[column];
        }

        @Override
        public Object getValueAt(int rowIndex, int columnIndex) {
            RosterEntry entry = roster.get(rowIndex);
            switch (columnIndex) {
                case 0:
                    return entry.getCost();
                case 1:
                    return entry.getCategory().getName();
                case 2:
                    return entry.getUnit().getShortName();
                case 3:
                    return entry.getNumber();
                case 4:
                    return entry.getOptionsSummary();
                default:
                    return entry.getUnit().getName();
            }
        }

        @Override
        public Class<?> getColumnClass(int columnIndex) {
            if (columnIndex == 0 || columnIndex == 3) {
                return Integer.class;
            }
            return Object.class;
        }

    }

    public Army getArmy() {
        return army;
    }

    public List<RosterEntry> getRoster() {
        return roster;
    }

}
